package com.login.framework;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.asynccommand.framework.BaseCommand;
import com.asynccommand.framework.CommandsController;
import com.asynccommand.framework.ICommandListener;
import com.login.framework.core.BaseLoginCommand;
import com.login.framework.core.LoginActionParamsCodes;
import com.login.framework.core.LoginActionsIDs;
import com.login.framework.core.LoginCommandFactory;
import com.login.framework.core.xmlcommands.LoginXMLCommandFactory;
import com.login.framework.model.User;

public final class LoginFramework implements ICommandListener {

	private static LoginFramework instance;

	private BaseLoginCommand loginCommand;

	private LoginConfig config;

	private ArrayList<ILoginListener> listeners;

	public static LoginFramework get() {
		if (instance == null) {
			instance = new LoginFramework();
		}
		return instance;
	}

	/**
	 * Debe utilizarse para iniciar el framework antes de ejecutar cualquier
	 * otra tarea.
	 * 
	 * @param config
	 * @param factory
	 */
	public void init(LoginConfig config, LoginCommandFactory factory) {
		this.config = config;
		loginCommand = factory.createLoginCommand();
		listeners = new ArrayList<ILoginListener>();
		CommandsController.get().register(this);
	}

	/**
	 * Debe utilizarse para iniciar el framework antes de ejecutar cualquier
	 * otra tarea. Utiliza Commands de login por defecto basados en un
	 * repositorio xml.
	 * 
	 * @param config
	 */
	public void init(LoginConfig config) {
		init(config, new LoginXMLCommandFactory());
	}

	/**
	 * Debe utilizarse para iniciar el framework antes de ejecutar cualquier
	 * otra tarea. Utiliza configuracion por defecto y Commands de login por
	 * defecto basados en un repositorio xml.
	 */
	public void init() {
		init(new LoginConfig() {

			@Override
			public boolean logEnabled() {
				return true;
			}

			@Override
			public int blackListTimeInMinutes() {
				return 10;
			}

			@Override
			public boolean blackListEnabled() {
				return true;
			}
		}, new LoginXMLCommandFactory());
	}

	/**
	 * Devuelve la configuración actual del framework.
	 * 
	 * @return
	 */
	public LoginConfig getConfig() {
		return this.config;
	}

	/**
	 * Registra los listeners del command de login
	 * 
	 * @param listener
	 */
	public void register(ILoginListener listener) {
		this.listeners.add(listener);
	}

	/**
	 * Elimina los listeners del command de login
	 * 
	 * @param listener
	 */
	public void unregister(ILoginListener listener) {
		this.listeners.remove(listener);
	}

	/**
	 * Ejecuta el command de login.
	 * 
	 * @param username
	 * @param password
	 */
	public void performLogin(String username, String password) {
		HashMap<String, Object> params = new HashMap<String, Object>();
		params.put(LoginActionParamsCodes.PARAM_USERNAME, username);
		params.put(LoginActionParamsCodes.PARAM_PASSWORD, password);
		loginCommand.execute(params);
	}

	/**
	 * 
	 * Devuelve el usuario logueado actual.
	 * 
	 * @return
	 */
	public User getLoggedUser() {
		return loginCommand.getLoggedUser();
	}

	/**
	 * Devuelve si existe un usuario logueado.
	 * 
	 * @return
	 */
	public boolean isUserLogged() {
		return loginCommand.getLoggedUser() != null;
	}

	@Override
	public final void onDone(int actionID, Map<String, Object> params) {
		switch (actionID) {
		case LoginActionsIDs.LOGIN:
			for (ILoginListener listener : this.listeners) {
				listener.onLoginDone();
			}
			break;

		default:
			break;
		}
	}

	@Override
	public final void onProgress(int actionID, Map<String, Object> params) {
		switch (actionID) {
		case LoginActionsIDs.LOGIN:
			for (ILoginListener listener : this.listeners) {
				listener.onLoginProgress();
			}
			break;

		default:
			break;
		}
	}

	@Override
	public final void onError(int actionID, Map<String, Object> params) {
		switch (actionID) {
		case LoginActionsIDs.LOGIN:
			for (ILoginListener listener : this.listeners) {
				listener.onLoginError((String) params
						.get(BaseCommand.ERROR_MSG));
			}
			break;

		default:
			break;
		}
	}
}
